package com.mindskip.xzs.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.mindskip.xzs.component.QywxComponent;
import com.mindskip.xzs.constant.CommonRedisKey;
import com.mindskip.xzs.domain.Department;
import com.mindskip.xzs.domain.DepartmentUser;
import com.mindskip.xzs.domain.User;
import com.mindskip.xzs.domain.enums.RoleEnum;
import com.mindskip.xzs.domain.enums.UserStatusEnum;
import com.mindskip.xzs.exception.BusinessException;
import com.mindskip.xzs.repository.NewUserMapper;
import com.mindskip.xzs.service.*;
import com.mindskip.xzs.viewmodel.admin.qywx.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

/**
 * <p>
 *
 * </p>
 *
 * @author guoguangkai
 * @since 2022/9/13
 */
@Slf4j
@Service
public class QywxServiceImpl implements QywxService {

    @Resource
    private QywxComponent qywxComponent;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private DepartmentService departmentService;
    @Resource
    private NewUserService userService;
    @Resource
    private NewUserMapper newUserMapper;
    @Resource
    private DepartmentUserService departmentUserService;
    @Resource
    private AuthenticationService authenticationService;
    @Value("${student.pc.pwd}")
    private String defaultPwd;
    @Value("${student.pc.image}")
    private String imagePath;

    @Override
    public List<QywxDepartment> getDepartmentList(Long id) {
        String accessToken = qywxComponent.getAccessToken();
        String response = HttpUtil.get("https://qyapi.weixin.qq.com/cgi-bin/department/list", new HashMap<String, Object>(3) {
            private static final long serialVersionUID = 8176338237055182571L;
            {
                put("access_token", accessToken);
                if (id != null && id > 0L) {
                    put("id", id);
                }
            }
        });
        if (StringUtils.isBlank(response)) {
            log.error("远程调用企业微信接口获取部门列表失败，http请求返回null，部门id：{}", id);
            throw new BusinessException("与企业微信内部系统通信失败，请稍后重试");
        }
        QywxDepartmentResult qywxDepartmentResult;
        try {
            qywxDepartmentResult = JSONObject.parseObject(response, QywxDepartmentResult.class);
        } catch (Exception e) {
            log.error("远程调用企业微信接口获取部门列表，json解析失败，返回原始内容：{}", response);
            throw new BusinessException("与企业微信内部系统通信失败，请稍后重试");
        }
        if (qywxDepartmentResult == null) {
            log.error("远程调用企业微信接口获取部门列表失败，http请求返回null");
            throw new BusinessException("与企业微信内部系统通信失败，请稍后重试");
        }
        if (!Long.valueOf(0).equals(qywxDepartmentResult.getErrCode())) {
            log.error("远程调用企业微信接口获取部门列表失败出错，返回code：{}，msg：{}", qywxDepartmentResult.getErrCode(), qywxDepartmentResult.getErrMsg());
            throw new BusinessException("与企业微信内部系统通信失败，请稍后重试");
        }
        return qywxDepartmentResult.getDepartment();
    }

    /**
     * 如需获取该部门及其子部门的所有成员，需先获取该部门下的子部门，然后再获取子部门下的部门成员，逐层递归获取。
     * @param departmentId 获取的部门id
     */
    @Override
    public List<QywxUser> getUserList(Long departmentId) {
        String accessToken = qywxComponent.getAccessToken();
        String response = HttpUtil.get("https://qyapi.weixin.qq.com/cgi-bin/user/simplelist", new HashMap<String, Object>(3) {
            private static final long serialVersionUID = 8176338237055182571L;
            {
                put("access_token", accessToken);
                put("department_id", departmentId);
            }
        });
        if (StringUtils.isBlank(response)) {
            log.error("远程调用企业微信接口获取编号为{}的部门成员失败，http请求返回null", departmentId);
            throw new BusinessException("与企业微信内部系统通信失败，请稍后重试");
        }
        QywxUserResult qywxUserResult;
        try {
            qywxUserResult = JSONObject.parseObject(response, QywxUserResult.class);
        } catch (Exception e) {
            log.error("远程调用企业微信接口获取编号为{}的部门成员列表，json解析失败，返回原始内容：{}", departmentId, response);
            throw new BusinessException("与企业微信内部系统通信失败，请稍后重试");
        }
        if (qywxUserResult == null) {
            log.error("远程调用企业微信接口获取编号为{}的部门成员列表，http请求返回null",departmentId);
            throw new BusinessException("与企业微信内部系统通信失败，请稍后重试");
        }
        if (!Long.valueOf(0).equals(qywxUserResult.getErrCode())) {
            log.error("远程调用企业微信接口获取编号为{}的部门成员列表出错，返回code：{}，msg：{}", departmentId, qywxUserResult.getErrCode(), qywxUserResult.getErrMsg());
            throw new BusinessException("与企业微信内部系统通信失败，请稍后重试");
        }
        return qywxUserResult.getUserlist();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public QywxDepartmentTree getDepartAndUserTree(Boolean useCache) {
        // 初始化选择公平锁、非公平锁
        ReentrantLock reentrantLock = new ReentrantLock(true);
        reentrantLock.lock();
        try {
            if (useCache == null || useCache) {
                QywxDepartmentTree tree = (QywxDepartmentTree) redisTemplate.opsForValue().get(CommonRedisKey.DEPART_USER_TREE_REDIS_KEY);
                if (tree != null) {
                    log.info("从缓存获取企业微信部门树");
                    return tree;
                }
            }
            // 获取全量部门集合
            List<QywxDepartment> allDepartmentList = getDepartmentList(null);
            QywxDepartmentTree qywxDepartmentTree = buildDepartUserTree(allDepartmentList);
            // 同步部门表
            LinkedList<Department> departmentPoList = new LinkedList<>();
            allDepartmentList.forEach(dept -> {
                Department department = new Department()
                        .setSort(dept.getOrder());
                BeanUtils.copyProperties(dept, department);
                departmentPoList.add(department);
            });
            departmentService.saveOrUpdateBatch(departmentPoList);
            // 同步用户表，部门用户中间表(所有删除重建)
            HashMap<String, Integer> dbUserMap = new HashMap<>();
            newUserMapper.selectList(
                    new LambdaQueryWrapper<User>()
                            .select(User::getId, User::getQywxId)
                            .eq(User::getDeleted, false)
                            .eq((User::getRole), RoleEnum.STUDENT.getCode())
            ).forEach(user -> dbUserMap.put(user.getQywxId(), user.getId()));
            ArrayList<QywxUser> allQywxUser = findAllUser(qywxDepartmentTree);
            LinkedList<User> insertUserPoList = new LinkedList<>();
            LinkedList<User> upsetUserPoList = new LinkedList<>();
            LinkedList<Integer> delUserIdList = new LinkedList<>();
            LinkedList<User> allUserPoList = new LinkedList<>();
            LinkedList<DepartmentUser> allDepartmentUserList = new LinkedList<>();
            List<String> qywxUserIds = allQywxUser.stream().map(QywxUser::getUserid).collect(Collectors.toList());
            dbUserMap.forEach((qywxId,id) -> {
                if (!qywxUserIds.contains(qywxId)) {
                    delUserIdList.add(id);
                }
            });
            allQywxUser.forEach(user -> {
                        User userPo = new User()
                                .setUserName(user.getName())
                                .setRealName(user.getName())
                                .setRole(RoleEnum.STUDENT.getCode())
                                .setQywxId(user.getUserid())
                                .setDeleted(false)
                                .setUserUuid(UUID.randomUUID().toString())
                                .setImagePath(imagePath)
                                .setStatus(UserStatusEnum.Enable.getCode());
                        Integer dbId = dbUserMap.get(user.getUserid());
                        if (dbId == null) {
                            userPo.setCreateTime(new Date())
                                    .setPassword(authenticationService.pwdEncode(defaultPwd));
                            insertUserPoList.add(userPo);
                        } else {
                            userPo.setId(dbId);
                            upsetUserPoList.add(userPo);
                        }
                        allUserPoList.add(userPo);

                        // 中间表
                        if (CollectionUtil.isNotEmpty(user.getDepartment())) {
                            user.getDepartment().forEach(deptId ->
                                    allDepartmentUserList.add(
                                            new DepartmentUser()
                                                    .setDeptId(deptId)
                                                    .setUserQywxId(user.getUserid())
                                    )
                            );
                        }
                    }
            );
            if (CollectionUtil.isNotEmpty(insertUserPoList)) {
                // 根据用户企业微信id去重
                List<User> uniqueUserList = insertUserPoList.stream().collect(
                        Collectors.collectingAndThen(
                                Collectors.toCollection(() ->
                                        new TreeSet<User>(Comparator.comparing(User::getQywxId))), ArrayList::new
                        )
                );
                userService.saveBatch(uniqueUserList);
            }
            if (CollectionUtil.isNotEmpty(upsetUserPoList)) {
                // 根据用户企业微信id去重
                List<User> uniqueUserList = upsetUserPoList.stream().collect(
                        Collectors.collectingAndThen(
                                Collectors.toCollection(() ->
                                        new TreeSet<User>(Comparator.comparing(User::getQywxId))), ArrayList::new
                        )
                );
                userService.updateBatchById(uniqueUserList);
            }
            if (CollectionUtil.isNotEmpty(delUserIdList)) {
                delUserIdList.forEach(delId -> {
                    userService.updateById(new User().setId(delId).setStatus(UserStatusEnum.Disable.getCode()).setModifyTime(new Date()));
                });
            }
            if (CollectionUtil.isNotEmpty(allDepartmentUserList)) {
                departmentUserService.remove(
                        new LambdaUpdateWrapper<DepartmentUser>()
                                .eq(DepartmentUser::getSideline, false)
                                .in(DepartmentUser::getUserQywxId,
                                        allDepartmentUserList.stream().map(DepartmentUser::getUserQywxId).collect(Collectors.toList()))
                );
                departmentUserService.saveBatch(allDepartmentUserList.stream().distinct().collect(Collectors.toList()));
            }

            // 因为只有这里一个入口修改用户信息，所以可以将用户信息缓存起来
            redisTemplate.opsForValue().set(CommonRedisKey.ALL_EMPLOYEE_INFO_KEY, allUserPoList, 30, TimeUnit.DAYS);
            // 已缓存token批量删除
          // Set<String> keys = redisTemplate.keys(CommonRedisKey.EMPLOYEE_QYWX_XCX_LOGIN_KEY + '*');
          // if (CollectionUtil.isNotEmpty(keys)) {
          //     redisTemplate.delete(keys);
          // }

            // 有效期10天
            redisTemplate.opsForValue().set(CommonRedisKey.DEPART_USER_TREE_REDIS_KEY, qywxDepartmentTree, 10, TimeUnit.DAYS);
            log.info("远程调用企业微信接口获取部门及人员数据，构建树，并放入缓存");
            return qywxDepartmentTree;
        } finally {
            reentrantLock.unlock();
        }
    }

    private QywxDepartmentTree buildDepartUserTree(List<QywxDepartment> allDepartmentList) {
        // 获取根节点，根部门为1
        QywxDepartment rootDepart = allDepartmentList.stream()
                .filter(department -> Long.valueOf(1L).equals(department.getId()))
                .findFirst()
                .orElseThrow(() -> new BusinessException("组织架构中公司节点不能为空"));
        // 获取根节点用户集合
        QywxDepartmentTree departmentTree = new QywxDepartmentTree();
        BeanUtils.copyProperties(rootDepart, departmentTree);
        rootDepart.setAncestors("0");
        departmentTree.setAncestors("0");
        handleUserAndChildDept(departmentTree, allDepartmentList);

        return departmentTree;
    }

    /**
     * 递归获取所有用户
     */
    private ArrayList<QywxUser> findAllUser(QywxDepartmentTree qywxDepartmentTree) {
        ArrayList<QywxUser> allUserList = new ArrayList<>();
        // 单独处理最外层
        if (CollectionUtil.isNotEmpty(qywxDepartmentTree.getUsers())) {
            allUserList.addAll(qywxDepartmentTree.getUsers());
        }
        // 处理各部门及子部门下的数据
        findAllUserInChildDept(qywxDepartmentTree, allUserList);
        return allUserList;
    }

    private void findAllUserInChildDept(QywxDepartmentTree qywxDepartmentTree, ArrayList<QywxUser> allUserList) {
        if (CollectionUtil.isNotEmpty(qywxDepartmentTree.getChildDepartments())) {
            qywxDepartmentTree.getChildDepartments().forEach(department -> {
                // 本级
                if (CollectionUtil.isNotEmpty(department.getUsers())) {
                    allUserList.addAll(department.getUsers());
                }
                // 子级
                if (CollectionUtil.isNotEmpty(department.getChildDepartments())) {
                    department.getChildDepartments().forEach(childDept -> {
                        if (CollectionUtil.isNotEmpty(childDept.getUsers())) {
                            allUserList.addAll(childDept.getUsers());
                        }
                        findAllUserInChildDept(childDept, allUserList);
                    });
                }
            });
        }
    }

    private void handleUserAndChildDept(QywxDepartmentTree parentDepartmentTree, List<QywxDepartment> departmentList) {
        StringBuilder ancestorsBuilder = new StringBuilder().append(parentDepartmentTree.getAncestors()).append(",").append(parentDepartmentTree.getId());
        parentDepartmentTree.setChildDepartments(
                        departmentList.stream()
                                .filter(department -> parentDepartmentTree.getId().equals(department.getParentId()))
                                .map(department -> {
                                    QywxDepartmentTree childDepartmentTree = new QywxDepartmentTree();
                                    BeanUtils.copyProperties(department, childDepartmentTree);
                                    department.setAncestors(ancestorsBuilder.toString());
                                    childDepartmentTree.setAncestors(ancestorsBuilder.toString());
                                    handleUserAndChildDept(childDepartmentTree, departmentList);
                                    return childDepartmentTree;
                                }).collect(Collectors.toList())
                )
                .setUsers(getUserList(parentDepartmentTree.getId()).stream()
                        .filter(user -> user.getDepartment().contains(parentDepartmentTree.getId()))
                        .collect(Collectors.toList()));
    }

    @Override
    public List<QywxDepartmentTreeV1> getDepartAndUserTreeV1() {
        QywxDepartmentTree departAndUserTree = getDepartAndUserTree(true);
        if (departAndUserTree == null) {
            return Collections.emptyList();
        }
        ArrayList<QywxDepartmentTreeV1> resList = new ArrayList<>();
        // 根节点部门
        QywxDepartmentTreeV1 rootQywxDepartmentTreeV1 = new QywxDepartmentTreeV1()
                .setId(departAndUserTree.getId())
                .setType(1)
                .setParentid(departAndUserTree.getParentId())
                .setLabel(departAndUserTree.getName());

        // 根节点部门下面的子节点
        findChildTree(departAndUserTree, rootQywxDepartmentTreeV1);
        resList.add(rootQywxDepartmentTreeV1);
        return resList;
    }


    private void findChildTree(QywxDepartmentTree departAndUserTree, QywxDepartmentTreeV1 qywxDepartmentTreeV1) {
        ArrayList<QywxDepartmentTreeV1> childList = new ArrayList<>();
        // 员工
        if (CollectionUtil.isNotEmpty(departAndUserTree.getUsers())) {
            departAndUserTree.getUsers().forEach(user -> {
                childList.add(
                        new QywxDepartmentTreeV1()
                                .setId(user.getUserid())
                                .setType(2)
                                .setParentid(departAndUserTree.getId())
                                .setLabel(user.getName())
                );
            });
        }

        // 部门
        if (CollectionUtil.isNotEmpty(departAndUserTree.getChildDepartments())) {
            departAndUserTree.getChildDepartments().forEach(childDepartment -> {
                QywxDepartmentTreeV1 deptQywxDepartmentTreeV1 = new QywxDepartmentTreeV1()
                        .setId(childDepartment.getId())
                        .setType(1)
                        .setParentid(childDepartment.getParentId())
                        .setLabel(childDepartment.getName());
                childList.add(deptQywxDepartmentTreeV1);

                findChildTree(childDepartment, deptQywxDepartmentTreeV1);
            });
        }

        qywxDepartmentTreeV1.setChildren(childList);
    }
}
